/*
 * FAT32 Formatter Tool
 * 格式化指定磁盘文件某分区为 FAT32
 */

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <math.h>

#define SECTOR_SIZE 512
#define RESERVED_SECTORS 32
#define NUM_FATS 2
#define ROOT_CLUSTER 2
#define FSINFO_SECTOR 1
#define BACKUP_BOOT_SECTOR 6

// FAT32 Boot Sector structure
#pragma pack(push, 1)
typedef struct {
    uint8_t jmpBoot[3];
    char OEMName[8];
    uint16_t BytsPerSec;
    uint8_t SecPerClus;
    uint16_t RsvdSecCnt;
    uint8_t NumFATs;
    uint16_t RootEntCnt;
    uint16_t TotSec16;
    uint8_t Media;
    uint16_t FATSz16;
    uint16_t SecPerTrk;
    uint16_t NumHeads;
    uint32_t HiddSec;
    uint32_t TotSec32;

    uint32_t FATSz32;
    uint16_t ExtFlags;
    uint16_t FSVer;
    uint32_t RootClus;
    uint16_t FSInfo;
    uint16_t BkBootSec;
    uint8_t Reserved[12];
    uint8_t DrvNum;
    uint8_t Reserved1;
    uint8_t BootSig;
    uint32_t VolID;
    char VolLab[11];
    char FilSysType[8];
    uint8_t BootCode[420];
    uint16_t Signature_word;
} FAT32_BootSector;

// FSInfo Sector
typedef struct {
    uint32_t LeadSig;
    uint8_t Reserved1[480];
    uint32_t StructSig;
    uint32_t FreeCount;
    uint32_t NxtFree;
    uint8_t Reserved2[12];
    uint32_t TrailSig;
} FAT32_FSInfo;
#pragma pack(pop)

void write_sector(int fd, uint32_t lba, const void* buffer) {
    lseek(fd, lba * SECTOR_SIZE, SEEK_SET);
    write(fd, buffer, SECTOR_SIZE);
}

void zero_fill(int fd, uint32_t start_lba, uint32_t count) {
    uint8_t zero[SECTOR_SIZE] = {0};
    for (uint32_t i = 0; i < count; ++i) {
        write_sector(fd, start_lba + i, zero);
    }
}

int format_fat32(const char* img_path, uint32_t start_lba, uint32_t total_sectors, uint8_t sec_per_clus) {
    int fd = open(img_path, O_RDWR);
    if (fd < 0) {
        perror("open");
        return -1;
    }

    uint32_t data_sectors, total_clusters, fat_sz;
    FAT32_BootSector bpb = {0};
    FAT32_FSInfo fsinfo = {0};

    // 初步估算 FAT 表大小
    data_sectors = total_sectors - RESERVED_SECTORS - (NUM_FATS * 1); // 假设FAT大小=1
    total_clusters = data_sectors / sec_per_clus;
    fat_sz = (uint32_t)ceil((total_clusters * 4.0) / SECTOR_SIZE);
    data_sectors = total_sectors - RESERVED_SECTORS - (NUM_FATS * fat_sz);
    total_clusters = data_sectors / sec_per_clus;
    fat_sz = (uint32_t)ceil((total_clusters * 4.0) / SECTOR_SIZE);

    // 构建 BPB
    memcpy(bpb.jmpBoot, "\xEB\x58\x90", 3);
    memcpy(bpb.OEMName, "fuquOS  ", 8);
    bpb.BytsPerSec = SECTOR_SIZE;
    bpb.SecPerClus = sec_per_clus;
    bpb.RsvdSecCnt = RESERVED_SECTORS;
    bpb.NumFATs = NUM_FATS;
    bpb.RootEntCnt = 0;
    bpb.TotSec16 = 0;
    bpb.Media = 0xF8;
    bpb.FATSz16 = 0;
    bpb.SecPerTrk = 63;
    bpb.NumHeads = 255;
    bpb.HiddSec = start_lba;
    bpb.TotSec32 = total_sectors;
    bpb.FATSz32 = fat_sz;
    bpb.ExtFlags = 0;
    bpb.FSVer = 0;
    bpb.RootClus = ROOT_CLUSTER;
    bpb.FSInfo = FSINFO_SECTOR;
    bpb.BkBootSec = BACKUP_BOOT_SECTOR;
    bpb.DrvNum = 0x80;
    bpb.BootSig = 0x29;
    bpb.VolID = 0x12345678;
    memcpy(bpb.VolLab, "FUQUVOL    ", 11);
    memcpy(bpb.FilSysType, "FAT32   ", 8);
    bpb.Signature_word = 0xAA55;

    // 写入 BPB
    write_sector(fd, start_lba + 0, &bpb);
    // 写入备份 BPB
    write_sector(fd, start_lba + BACKUP_BOOT_SECTOR, &bpb);

    // 构建 FSINFO
    fsinfo.LeadSig = 0x41615252;
    fsinfo.StructSig = 0x61417272;
    fsinfo.FreeCount = 0xFFFFFFFF;
    fsinfo.NxtFree = 0x00000003;
    fsinfo.TrailSig = 0xAA550000;
    write_sector(fd, start_lba + FSINFO_SECTOR, &fsinfo);

    // FAT初始化（仅FAT头3项）
    uint8_t fat_sector[SECTOR_SIZE] = {0};
    fat_sector[0] = 0xF8;
    fat_sector[1] = 0xFF;
    fat_sector[2] = 0xFF;
    fat_sector[3] = 0x0F;
    fat_sector[4] = 0xFF;
    fat_sector[5] = 0xFF;
    fat_sector[6] = 0xFF;
    fat_sector[7] = 0x0F;
    fat_sector[8] = 0xFF;
    fat_sector[9] = 0xFF;
    fat_sector[10] = 0xFF;
    fat_sector[11] = 0x0F;

    // 清空 FAT 区域并写入首扇区（两张表）
    zero_fill(fd, start_lba + RESERVED_SECTORS, fat_sz * NUM_FATS);
    write_sector(fd, start_lba + RESERVED_SECTORS, fat_sector);
    write_sector(fd, start_lba + RESERVED_SECTORS + fat_sz, fat_sector);

    // 清空根目录第一个簇
    zero_fill(fd, start_lba + RESERVED_SECTORS + fat_sz * NUM_FATS, sec_per_clus);

    close(fd);
    printf("FAT32 格式化完成，总扇区: %u, 每簇扇区: %u, FAT大小(扇区): %u\n",
        total_sectors, sec_per_clus, fat_sz);
    return 0;
}

int main(const int argc, char* argv[]) {
    if (argc != 5) {
        fprintf(stderr, "用法: %s <镜像路径> <起始LBA> <总扇区数> <每簇扇区数>\n", argv[0]);
        return 1;
    }
    const char* path = argv[1];
    uint32_t start = atoi(argv[2]);
    uint32_t total = atoi(argv[3]);
    uint8_t clus = atoi(argv[4]);

    return format_fat32(path, start, total, clus);
}
